package com.xiangxiao.rpan.storage.service.impl;

import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.EnumUtil;
import cn.hutool.core.util.ReflectUtil;
import cn.hutool.core.util.StrUtil;
import com.xiangxiao.rpan.storage.constant.GlobalConsts;
import com.xiangxiao.rpan.storage.constant.ResponseCode;
import com.xiangxiao.rpan.storage.constant.ResponseMessage;
import com.xiangxiao.rpan.storage.dao.StorageSourceConfigMapper;
import com.xiangxiao.rpan.storage.dao.StorageSourceMapper;
import com.xiangxiao.rpan.storage.dto.FileListConfigDto;
import com.xiangxiao.rpan.storage.dto.StorageSourceAllParamDTO;
import com.xiangxiao.rpan.storage.dto.StorageSourceDto;
import com.xiangxiao.rpan.storage.dto.VerifyResultDTO;
import com.xiangxiao.rpan.storage.entity.ReadmeConfig;
import com.xiangxiao.rpan.storage.entity.StorageSource;
import com.xiangxiao.rpan.storage.entity.StorageSourceConfig;
import com.xiangxiao.rpan.storage.entity.SupportStorage;
import com.xiangxiao.rpan.storage.enums.StorageTypeEnum;
import com.xiangxiao.rpan.storage.exception.StorageExcetion;
import com.xiangxiao.rpan.storage.factory.StorageSourceContext;
import com.xiangxiao.rpan.storage.service.*;
import com.xiangxiao.rpan.storage.utils.ConverUtils;
import com.xiangxiao.rpan.storage.vo.StorageSourceConfigVo;
import com.xiangxiao.rpan.storage.vo.StorageSourceVo;
import com.xiangxiao.rpan.utils.EnumConvertUtil;
import io.swagger.models.auth.In;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import com.alibaba.fastjson.JSON;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.lang.reflect.Field;
import java.text.DateFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.TimeUnit;

/**
 * @auther xiangxiao
 * @email 573768011@qq.com
 * @data 2023/6/30 17:03
 */
@Slf4j
@Service("storageSourceService")
public class StorageSourceServiceImpl implements StorageSourceService {
  private static Logger logger = LoggerFactory.getLogger(StorageSourceServiceImpl.class);
  @Resource
  private StringRedisTemplate stringRedisTemplate;
  @Value("${spring.redis.timeout}")
  private int timeout;
  @Resource
  private ConverUtils converUtils;
  @Resource
  private StorageSourceContext storageSourceContext;
  @Resource
  private StorageSourceService storageSourceService;
  @Resource
  private StorageSourceConfigService storageSourceConfigService;
  @Resource
  private PasswordConfigService passwordConfigService;
  @Resource
  private FilterConfigService filterConfigService;
  @Resource
  private ReadmeConfigService readmeConfigService;
  @Resource
  private StorageSourceMapper storageSourceMapper;
  @Resource
  private StorageSourceConfigMapper storageSourceConfigMapper;
  private final Class<StorageSourceVo> storageSourceVoClazz = StorageSourceVo.class;

  public StorageSourceServiceImpl() {
  }

  /**
   * 该类的依赖项全部注入,初始化完成后立马调用该方法(去初始化所有的存储源)
   * **/
  @PostConstruct
  public void intStorageSources() {
    List<StorageSource> list = storageSourceService.findAllOrderByOrderNum();
    for (StorageSource storageSource : list) {
      try {
        storageSourceContext.init(storageSource);
        logger.info("启动时初始化存储源成功, 存储源 id: [{}], 存储源类型: [{}], 存储源名称: [{}]",
            storageSource.getId(), storageSource.getType().getDescription(), storageSource.getName());
      } catch (Exception e) {
        logger.error("启动时初始化存储源失败, 存储源 id: {}, 存储源类型: {}, 存储源名称: {}",
            storageSource.getId(), storageSource.getType().getDescription(), storageSource.getName(), e);
      }
    }
  }
  @Override
  public List<StorageSourceVo> findAllEnableOrderByOrderNum() {
    List<StorageSourceVo> listVos = new ArrayList<>();
    List<StorageSource> list = storageSourceMapper.findListByEnableOrderByOrderNum();

    listVos = converUtils.entityToResultList(list);
    return listVos;
  }

  @Override
  public List<StorageSource> findAllOrderByOrderNum() {
    return storageSourceMapper.findAllOrderByOrderNum();
  }

  @Override
  public List<SupportStorage> getSupportStorages() {
    List<SupportStorage> types = new ArrayList<>();
    StorageTypeEnum[] values = StorageTypeEnum.values();
    for(StorageTypeEnum val : values) {
      SupportStorage storage = new SupportStorage();
      storage.setKey(val.toString());
      storage.setId(val.toString());
      storage.setDescription(val.getDescription());
      types.add(storage);
    };
    return types;
  }

  @Override
  public StorageTypeEnum findStorageTypeById(Integer id) {
    return Optional.ofNullable(findById(id)).map(StorageSource::getType).orElse(null);
  }


  @Override
  public StorageSource findById(Integer id) {
    return storageSourceMapper.selectById(id);
  }

  @Override
  public List<StorageSourceConfig> selectStorageConfigByStorageId(Integer storageId) {
      List<StorageSourceConfig> storageConfigs = storageSourceConfigMapper.findByStorageIdOrderById(storageId);
      return storageConfigs;
  }

  @Override
  public List<StorageSourceConfig> selectStorageConfigByStorageKey(String storageKey) {
    List<StorageSourceConfig> storageConfigs = storageSourceConfigMapper.findByStorageKeyOrderById(storageKey);
    return storageConfigs;
  }

  @Override
  public boolean existByStorageKey(String storageKey) {
    return findByStorageKey(storageKey) != null;
  }

  @Override
  public StorageSource findByStorageKey(String storageKey) {
    return storageSourceMapper.findByStorageKey(storageKey);
  }

  @Override
  public Integer saveStorageSource(StorageSourceDto storageSourceDto) {
    // 保存或更新存储源
    StorageSource storageSource = converUtils.saveRequestToEntity(storageSourceDto);
    // 保存或更新存储源
    StorageSource dbSaveResult = saveOrUpdate(storageSource);
    log.info("保存存储源成功, id: {}, name: {}, key: {}, type: {}",
        dbSaveResult.getId(), dbSaveResult.getName(),
        dbSaveResult.getKey(), dbSaveResult.getType().getDescription());
    // 存储源 ID
    Integer storageId = dbSaveResult.getId();
    // 保存存储源参数
    List<StorageSourceConfig> storageSourceConfigList =
        storageSourceConfigService.toStorageSourceConfigList(storageId,
            dbSaveResult.getType(),
            storageSourceDto.getStorageSourceAllParam());
    storageSourceConfigService.saveBatch(storageId, storageSourceConfigList);
    log.info("保存存储源参数成功，尝试根据参数初始化存储源, id: {}, name: {}, config size: {}",
        dbSaveResult.getId(), dbSaveResult.getName(), storageSourceConfigList.size());

    // 初始化并检查是否可用
    storageSourceContext.init(storageSource);
    log.info("根据参数初始化存储源成功, id: {}, name: {}, config size: {}",
        dbSaveResult.getId(), dbSaveResult.getName(), storageSourceConfigList.size());

    return storageId;
  }

  @Override
  public StorageSourceDto findDTOById(Integer id) {
    // 将参数列表通过反射写入到 StorageSourceAllParam 中.
    StorageSourceAllParamDTO storageSourceAllParam = new StorageSourceAllParamDTO();
    storageSourceService.selectStorageConfigByStorageId(id)
        .forEach(storageSourceConfig ->
            ReflectUtil.setFieldValue(storageSourceAllParam, storageSourceConfig.getName(), storageSourceConfig.getValue())
        );

    // 获取数据库对象，转为 dto 对象返回
    StorageSource storageSource = findById(id);
    return converUtils.entityToDTO(storageSource, storageSourceAllParam);
  }

  @Override
  public void updateById(StorageSource entity) {
    storageSourceMapper.updateStorageById(entity);
  }


  @Override
  public Integer findIdByKey(String storageKey) {
    return Optional.ofNullable(this.findByStorageKey(storageKey)).map(StorageSource::getId).orElse(null);
  }

  @Override
  public StorageSource deleteStorageById(Integer id) {
    StorageSource storageSource = this.findById(id);

    if (storageSource == null) {
      String msg = StrUtil.format("删除存储源时检测到 id 为 {} 的存储源不存在", id);
      throw new StorageExcetion(ResponseMessage.STORAGE_SOURCE_NOT_FOUND,  ResponseCode.STORAGE_SOURCE_NOT_FOUND);
    };

    String storageKey = storageSource.getKey();

    int deleteEntitySize = storageSourceMapper.deleteStorageById(id);
    int deleteConfigSize = storageSourceConfigService.deleteByStorageId(id);

    int clearPasswordSize = passwordConfigService.deleteByStorageId(id);
    int clearFilterSize = filterConfigService.deleteByStorageId(id);
//    int clearReadmeSize = readmeConfigService.deleteByStorageId(id);

//    int clearShortLinkSize = shortLinkService.deleteByStorageId(id);
//    int clearDownloadLogSize = downloadLogService.deleteByStorageKey(storageKey);

    storageSourceContext.destroy(id);

    return storageSource;
  }

  @Override
  public void updateStorageSourceConfigId(String key, Integer storageId) {

  }

  @Override
  public StorageSourceConfigVo getStorageConfigSource(FileListConfigDto fileListConfigDto) {
    StorageSourceConfigVo storageSourceConfigVo = new StorageSourceConfigVo();
    String storageKey = fileListConfigDto.getStorageKey();
    String path = fileListConfigDto.getPath();

    // 判断存储源是否存在.
    StorageSource storageSource = storageSourceService.findByStorageKey(storageKey);
    if (storageSource == null) {
      throw new StorageExcetion("通过存储源 key 未找到存储源, key: " + storageKey);
    };
    // 根据存储源 key 获取存储源 id
    Integer storageId = storageSource.getId();

    VerifyResultDTO verifyPassword = passwordConfigService.verifyPassword(storageId, path, fileListConfigDto.getPassword());

    ReadmeConfig readmeByPath = null;
    if (verifyPassword.isPassed()) {
      // 获取指定存储源路径下的 readme 信息
      readmeByPath = readmeConfigService.getByStorageAndPath(storageId, path, storageSource.getCompatibilityReadme());
    } else {
      log.info("文件夹密码验证失败，不获取 readme 信息, storageId: {}, path: {}, password: {}", storageId, path, fileListConfigDto.getPassword());
    };
    storageSourceConfigVo.setEnableFileOperator(storageSource.getEnableFileOperator());
    storageSourceConfigVo.setReadmeDisplayMode(readmeByPath.getDisplayMode());

    return storageSourceConfigVo;
  };




  /**
   * 保存或修改存储源设置，如果没有 id 则新增，有则更新，且会检测是否填写 key，如果没写，则自动将 id 设置为 key 并保存。
   * @param   storageSource
   *          存储源对象
   * @return  保存后对象
   */
  public StorageSource saveOrUpdate(StorageSource storageSource) {
    if (StrUtil.isEmpty(storageSource.getKey())) {
      storageSource.setKey(Convert.toStr(storageSource.getId()));
    };
    // 保存存储源基本信息,无id则说明是新增
    if (storageSource.getId() == null) {
      Integer count =  storageSourceMapper.insertStorage(storageSource);
//      storageSource.setId(id);
    } else {
      // 有id则说明是修改
      // 判断是否修改了存储源别名，如果修改了则清除之前存储源别名的缓存。
      StorageSource originStorageSource = storageSourceMapper.selectById(storageSource.getId());
      if (originStorageSource != null && !StrUtil.equals(originStorageSource.getKey(), storageSource.getKey())) {
        storageSourceMapper.updateStorageById(storageSource);
      }
    };
    return storageSource;
  }

}
